"use strict"

/**
 * @接触角的卷积神经网络处理模型
 * 参考了AlexNet卷积神经网络的重叠式池化层
 * 参考了VGG的一些意见
 * 以及各类卷积神经网络
 * 240919: 宋有义老师提了优化意见：
 *   1. 为更好应用(-1, 1)输出区间，应修改标签的归一化映射
 *   2. 为更好应用(-1, 1)输出区间，去掉relu激活函数，直接线性处理
 *   3. 去掉dropout层，最后全连接层应用L1L2正则化
 * softsign激活函数用于(-1,1)映射
 */

/**
 * @库导入
 */
// 导入tfjs和tfvis和库
import * as tf from "@tensorflow/tfjs"


/**
 * @建立模型
 * Hebbian Principle：神经网络中越接近输入的层的网络应该越稀疏
 */
export function createModel() {

  // 为求简便，直接使用tf.sequential()建立模型
  const model = tf.sequential({
    name: "contact-angle-model",
  })

  /**
   * @特征收束
   * 1~3层为特征收束层，用于缩小图像尺寸，提取特征
   */

  // 输入层：卷积层-1（不用激活函数）
  model.add(tf.layers.conv2d({
    name: "conv2d-1-input",
    // 输入层独有。输入空间形状，NHWC
    inputShape: [1152, 864, 3],
    // 滤波器数量，即输出的最后一层channels数量
    filters: 8,
    // 卷积核尺寸
    kernelSize: [3, 3],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 不启用偏差
    useBias: false,
  }))

  // 最大池化层-1：重叠式
  model.add(tf.layers.maxPooling2d({
    name: "max-pooling-1",
    // 池化尺寸
    poolSize: [3, 3],
    // 池化步长
    strides: [2, 2],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
  }))

  // 卷积层-2（不用激活函数）
  model.add(tf.layers.conv2d({
    name: "conv2d-2",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 16,
    // 卷积核尺寸
    kernelSize: [3, 3],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 不启用偏差
    useBias: false,
  }))

  // 最大池化层-2：重叠式
  model.add(tf.layers.maxPooling2d({
    name: "max-pooling-2",
    // 池化尺寸
    poolSize: [3, 3],
    // 池化步长
    strides: [2, 2],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
  }))

  // 卷积层-3（不用激活函数）
  model.add(tf.layers.conv2d({
    name: "conv2d-3",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 32,
    // 卷积核尺寸
    kernelSize: [3, 3],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 不启用偏差
    useBias: false,
  }))

  // 最大池化层-3：重叠式
  model.add(tf.layers.maxPooling2d({
    name: "max-pooling-3",
    // 池化尺寸
    poolSize: [3, 3],
    // 池化步长
    strides: [2, 2],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
  }))

  /**
   * @过渡
   * 第4~5层，由特征收束层过渡到特征处理
   */

  // 卷积层-4
  model.add(tf.layers.conv2d({
    name: "conv2d-4",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 64,
    // 卷积核尺寸
    kernelSize: [1, 1],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 启用偏置
    useBias: true,
    // 激活函数
    activation: "softsign",
  }))

  // 最大池化层-4
  model.add(tf.layers.maxPooling2d({
    name: "max-pooling-4",
    // 池化尺寸
    poolSize: [3, 3],
    // 池化步长
    strides: [2, 2],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
  }))

  /**
   * @特征处理
   * 第5~7层，此时图片尺寸已经很好了，着重处理特征
   */

  // 卷积层-5a（不用激活函数）
  model.add(tf.layers.conv2d({
    name: "conv2d-5a",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 64,
    // 卷积核尺寸
    kernelSize: [3, 3],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 不启用偏差
    useBias: false,
  }))

  // 卷积层-5b
  model.add(tf.layers.conv2d({
    name: "conv2d-5b",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 128,
    // 卷积核尺寸
    kernelSize: [1, 1],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 启用偏置
    useBias: true,
    // 激活函数
    activation: "softsign",
  }))

  // 最大池化层-5
  model.add(tf.layers.maxPooling2d({
    name: "max-pooling-5",
    // 池化尺寸
    poolSize: [3, 3],
    // 池化步长
    strides: [2, 2],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
  }))

  // 卷积层-6a（不用激活函数）
  model.add(tf.layers.conv2d({
    name: "conv2d-6a",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 128,
    // 卷积核尺寸
    kernelSize: [3, 3],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 不启用偏差
    useBias: false,
  }))

  // 卷积层-6b
  model.add(tf.layers.conv2d({
    name: "conv2d-6b",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 256,
    // 卷积核尺寸
    kernelSize: [1, 1],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 启用偏置
    useBias: true,
    // 激活函数
    activation: "softsign",
  }))

  // 最大池化层-6
  model.add(tf.layers.maxPooling2d({
    name: "max-pooling-6",
    // 池化尺寸
    poolSize: [3, 3],
    // 池化步长
    strides: [3, 3],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
  }))

  // 卷积层-7a（不用激活函数）
  model.add(tf.layers.conv2d({
    name: "conv2d-7a",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 256,
    // 卷积核尺寸
    kernelSize: [3, 3],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 不启用偏差
    useBias: false,
  }))

  // 卷积层-7b
  model.add(tf.layers.conv2d({
    name: "conv2d-7b",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 512,
    // 卷积核尺寸
    kernelSize: [1, 1],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 启用偏置
    useBias: true,
    // 激活函数
    activation: "softsign",
  }))

  // 最大池化层-7
  model.add(tf.layers.maxPooling2d({
    name: "max-pooling-7",
    // 池化尺寸
    poolSize: [3, 3],
    // 池化步长
    strides: [3, 3],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
  }))

  /**
   * @预扁平
   * 此时图片尺寸已经是4x3了，可以开始扁平化 + 全连接处理
   */

  // 卷积层-8a（不用激活函数）
  model.add(tf.layers.conv2d({
    name: "conv2d-8a",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 512,
    // 卷积核尺寸
    kernelSize: [3, 3],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 不启用偏差
    useBias: false,
  }))

  // 卷积层-8b
  model.add(tf.layers.conv2d({
    name: "conv2d-8b",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 1024,
    // 卷积核尺寸
    kernelSize: [1, 1],
    // 卷积步长
    strides: [1, 1],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 启用偏置
    useBias: true,
    // 激活函数
    activation: "softsign",
  }))

  // 平均池化层-8
  model.add(tf.layers.maxPooling2d({
    name: "max-pooling-8",
    // 池化尺寸
    poolSize: [4, 3],
    // 池化步长
    strides: [4, 3],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
  }))

  // 扁平化层
  model.add(tf.layers.flatten({
    name: "flatten",
  }))

  // 全连接层（不用激活函数）
  model.add(tf.layers.dense({
    name: "dense-1",
    // 输出空间的维度
    units: 128,
    // 不启用偏置
    useBias: false,
    // 核(权重)正则化：L1L2正则化器
    kernelRegularizer: tf.regularizers.l1l2(),
  }))

  // 输出层：全连接层
  model.add(tf.layers.dense({
    name: "dense-2-output",
    // 输出空间的维度
    units: 1,
    // 启用偏置
    useBias: true,
    // 激活函数
    activation: "softsign",
    // 核(权重)正则化：L1L2正则化器
    kernelRegularizer: tf.regularizers.l1l2(),
    // 偏置正则化：L1L2正则化器
    biasRegularizer: tf.regularizers.l1l2(),
  }))

  // 返回模型
  return model

}

